/**
 * Created by xinxinran on 15/8/29.
 */
'use strict';
var util = require('util'),
    mongooseModel = require('mongoose').Model,
    crypto = require('crypto');

function isFunction(fn){
    return typeof fn === 'function';
}

exports.isArrayLike = function(obj, includeString) {
    if(includeString && typeof obj === "string")
        return false;
    if (obj && typeof obj === "object") {
        var n = obj.length;
        if (+n === n && !(n % 1) && n >= 0) {
            try {
                if ({}.propertyIsEnumerable.call(obj, 'length') === false) {
                    return Array.isArray(obj) || /^\s?function/.test(obj.item || obj.callee);
                }
                return true;
            } catch (e) {
                return true;
            }
        }
    }
    return false;
};

exports.each = function(obj, fn, scope, map) {
    var value, i = 0,
        isArray = exports.isArrayLike(obj),
        ret = [];
    if (isArray) {
        for (var n = obj.length; i < n; i++) {
            value = fn.call(scope || obj[i], i, obj[i]);
            if (map) {
                if (value != null) {
                    ret[ ret.length ] = value;
                }
            } else if (value === false) {
                break;
            }
        }
    } else {
        for (i in obj) {
            value = fn.call(scope || obj[i], i, obj[i]);
            if (map) {
                if (value != null) {
                    ret[ ret.length ] = value;
                }
            } else if (value === false) {
                break;
            }
        }
    }
    return map ? ret : obj;
};

exports.scopeProxy = function( fn, context ) {
    var tmp, args, proxy, slice = Array.prototype.slice;

    if ( typeof context === "string" ) {
        tmp = fn[ context ];
        context = fn;
        fn = tmp;
    }

    if ( !isFunction( fn ) ) {
        return undefined;
    }

    // Simulated bind
    args = slice.call( arguments, 2 );
    proxy = function() {
        return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
    };

    return proxy;
};

exports.extendObj = function(model, obj){
    var idx = 1, args = [].slice.call(arguments), key,
        ride = typeof args[args.length - 1] === "boolean" ? args.pop() : true;

    obj = util.isArray(obj) ? obj[0] : obj;
    if(!obj){
        return;
    }

    if(args.length === 1){
        model = {};
        idx = 0;
    }

    while(obj = args[idx++]){
        for(key in obj){
            if(obj.hasOwnProperty(key) && (ride || !(key in model))){
                (model[key] = obj[key]);
            }
        }
    }

    return model;
};

exports.uuid = function(len, radix) {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
    var uuid = [], i, r;
    radix = radix || chars.length;

    if (len) {
        // Compact form
        for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
    } else if(len === false) {
        // rfc4122, version 4 form

        // rfc4122 requires these characters
        uuid[12] = '4';

        // Fill in random data.  At i==19 set the high bits of clock sequence as
        // per rfc4122, sec. 4.1.5
        for (i = 0; i < 32; i++) {
            if (!uuid[i]) {
                r = 0 | Math.random() * 16;
                uuid[i] = chars[(i == 16) ? (r & 0x3) | 0x8 : r];
            }
        }
    }else {
        // rfc4122, version 4 form

        // rfc4122 requires these characters
        uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
        uuid[14] = '4';

        // Fill in random data.  At i==19 set the high bits of clock sequence as
        // per rfc4122, sec. 4.1.5
        for (i = 0; i < 36; i++) {
            if (!uuid[i]) {
                r = 0 | Math.random() * 16;
                uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
            }
        }
    }

    return uuid.join('');
};

exports.toObject = function(obj){
    if(obj instanceof mongooseModel){
        return obj.toObject();
    }
    return obj;
};

exports.md5Hex = function(str){
    var md5sum = crypto.createHash('md5');
    md5sum.update(new Buffer(str));
    str = md5sum.digest('hex');
    return str;
};

exports.hashPassword = function(passwd){
    return exports.md5Hex('%^$#&#@' + passwd);
};

exports.fixArrayOrderById = function(sortedIds, objArray, idField){
    var arrayMapById, res = [];
    if(!sortedIds || !objArray || !idField || !exports.isArrayLike(objArray)){
        return res;
    }

    arrayMapById = {};

    exports.each(objArray, function(_, obj){
        arrayMapById[obj[idField]] = obj;
    });

    exports.each(sortedIds, function(_, thisId){
        var thisObj = arrayMapById[thisId];
        thisObj && res.push(thisObj);
    });

    return res;
};

Date.prototype.Format = function(fmt)
{ //author: meizz
    var o = {
        "M+" : this.getMonth()+1,                 //月份
        "d+" : this.getDate(),                    //日
        "h+" : this.getHours(),                   //小时
        "m+" : this.getMinutes(),                 //分
        "s+" : this.getSeconds(),                 //秒
        "q+" : Math.floor((this.getMonth()+3)/3), //季度
        "S"  : this.getMilliseconds()             //毫秒
    };
    if(/(y+)/.test(fmt))
        fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
    for(var k in o)
        if(new RegExp("("+ k +")").test(fmt))
            fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
    return fmt;
};

exports.getFormattedDate = function(d, format){
    if(d instanceof Date){
        if (format) {
            return d.Format(format);
        } else {
            return d.Format('yyyy-MM-dd hh:mm:ss');
        }
    }else{
        return d.toLocaleString();
    }
};

exports.formatString = function(txt, obj){
    var arr = Array.prototype.slice.call(arguments, 1);
    return txt.replace(/\\?#\{([^{}]+)}/gm,function(match, name){
        if(match.charAt(0) === '\\'){
            return match.slice(1);
        }
        var index = Number(name);
        if(index >= 0){
            return arr[index];
        }
        if(obj && obj[name] !== void 0){
            if(obj[name] instanceof Date){
                return exports.getFormattedDate(obj[name]);
            }
            return obj[name];
        }
        return '';
    });
};
